#include "FPCH.h"

#include "FGlyphMap.h"

#include "FGlyph.h"

namespace Font
{

	GlyphMap::GlyphMap(Library* a_Library, FaceHandle* a_Owner)
	{
		m_Library = a_Library;
		m_Owner = a_Owner;
		m_EntryDefault = NULL;
	}
	
	GlyphMap::~GlyphMap()
	{
		for (std::vector<GlyphEntry*>::iterator it = m_Entries.begin(); it != m_Entries.end(); )
		{
			delete *it;
			it = m_Entries.erase(it);
		}
	}

	GlyphEntry* GlyphMap::_BuildEntry(Glyph* a_Glyph, tb::Pos2& a_Position, tb::Pos2& a_Dimensions)
	{
		float multiplier_x = 1.f / (float)a_Dimensions.x;
		float multiplier_y = 1.f / (float)a_Dimensions.y;

		GlyphEntry* result = NULL;

		if (a_Glyph->CheckBitmapValid())
		{
			const tb::Pos2& dim = a_Glyph->GetBitmapDimensions();

			if (a_Position.x + dim.x >= a_Dimensions.y)
			{
				a_Position.x = 0;
				a_Position.y += m_Owner->GetHeightNewLine();
			}

			if (a_Position.y + dim.y > a_Dimensions.y)
			{
				return result;
			}

			result = new GlyphEntry;
			result->bitmap        = true;
			result->pos_start     = a_Glyph->GetBoundingBoxStart();
			result->pos_end       = a_Glyph->GetBoundingBoxEnd();
			result->cursor        = a_Position;
			result->tex_start.x   = multiplier_x * (result->cursor.x);
			result->tex_start.y   = multiplier_y * (result->cursor.y);
			result->tex_end.x     = multiplier_x * (result->cursor.x + dim.x);
			result->tex_end.y     = multiplier_y * (result->cursor.y + dim.y);

			a_Position.x += dim.x;
		}
		else
		{
			result = new GlyphEntry;
			result->bitmap = false;
		}

		result->glyph = a_Glyph;
		result->advance = (float)a_Glyph->GetAdvance().x;

		return result;
	}

	GlyphEntry* GlyphMap::GetGlyphEntry(wchar_t a_Character)
	{
		std::map<wchar_t, GlyphEntry*>::iterator found = m_EntriesByGlyph.find(a_Character);
		if (found != m_EntriesByGlyph.end()) 
		{ 
			return found->second; 
		}

		return m_EntryDefault;
	}

	Glyph* GlyphMap::GetGlyph(wchar_t a_Character)
	{
		return m_Owner->GetGlyph(a_Character);
	}

	void GlyphMap::SetDefault(wchar_t a_Character)
	{
		m_EntryDefault = NULL;

		std::map<wchar_t, GlyphEntry*>::iterator found = m_EntriesByGlyph.find(a_Character);
		if (found != m_EntriesByGlyph.end()) 
		{ 
			m_EntryDefault = found->second;
		}
	}

	void GlyphMap::PackGlyphs(const std::vector<Glyph*>& a_Glyphs, unsigned int a_MinLevel, bool a_Paging /*= true*/)
	{
		GlyphPage* page_curr = NULL;
		int page_id = 0;
		std::vector<GlyphEntry*> page_glyphs;

		int max_level = (a_Paging) ? (a_MinLevel + 1) : 15;

		for (int j = a_MinLevel; j < max_level; j++)
		{
			bool fits = true;

			int dimension = 1 << j;
			unsigned int found = 0;

			page_glyphs.clear();
			tb::Pos2 position(0, 0);
			tb::Pos2 size(dimension, dimension);

			for (size_t i = 0; i < a_Glyphs.size(); i++)
			{
				Glyph* curr = a_Glyphs[i];

				GlyphEntry* entry_curr = _BuildEntry(curr, position, size);
				if (!entry_curr)
				{
					if (a_Paging)
					{
						page_curr = new GlyphPage(m_Library, this);
						page_curr->SetDimensions(dimension, dimension);
						page_curr->WriteGlyphs(page_glyphs);
						m_Pages.push_back(page_curr);
						page_id++;

						page_glyphs.clear();
						position.x = 0;
						position.y = 0;
					}
					else
					{
						fits = false;
						break;
					}
				}
				else
				{
					m_Entries.push_back(entry_curr);
					m_EntriesByGlyph.insert(std::pair<wchar_t, GlyphEntry*>(curr->GetCharacter(), entry_curr));

					entry_curr->page_id = page_id;
					page_glyphs.push_back(entry_curr);
				}
				
				found++;
			}

			if (fits)
			{
				page_curr = new GlyphPage(m_Library, this);
				page_curr->SetDimensions(dimension, dimension);
				page_curr->WriteGlyphs(page_glyphs);
				m_Pages.push_back(page_curr);
			}
		}	
	}

	GlyphPage* GlyphMap::GetPage(int a_Index)
	{
		if ((size_t)a_Index < m_Pages.size())
		{
			return m_Pages[a_Index];
		}

		return NULL;
	}

	FaceHandle* GlyphMap::GetFont()
	{
		return m_Owner;
	}

}; // namespace Font